/*
    DIMVisual-KAAPI, the DIMVisual bundle for KAAPI trace files
    Copyright (c) 2008 Lucas Mello Schnorr <schnorr@gmail.com>

    This file is part of DIMVisual-KAAPI.

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
#include "KAAPIConverter.h"
#include <kaapi> /* for the trace and level stuff (identifier) */


@implementation KAAPIConverter
- (id) initWithProvider: (id<Integrator>) prov
{
	self = [super init];
/*
#ifdef ORGANIZATION_BY_PROCESS
	NSArray *entities = [[NSArray alloc] initWithObjects: @"gid", nil];
#else
	NSArray *entities = [[NSArray alloc] initWithObjects: @"gid", @"cid", nil];
#endif
	NSArray *ret = [prov entitiesExists: entities];
	if ([ret count] != 0){
		NSLog (@"KAAPIConverter: Entities %@ not defined in "
			"the hierarchy configuration provided.", entities);
		[super release];
		return nil;
	}
*/

	buffer = [[NSMutableArray alloc] init];
	links = [[NSMutableDictionary alloc] init];
	names = [[NSMutableDictionary alloc] init];
	mappingGidHostname = [[NSMutableDictionary alloc] init];
	workStealingLinks = [[NSMutableDictionary alloc] init];
	kernelRstealTimes = [[NSMutableDictionary alloc] init];


	provider = prov;
	return self;
}

- (void) dealloc
{
	[links release];
	[kernelRstealTimes release];
	[super dealloc];
}

/*
 *
 */
- (PajeSetState *) addPajeSetState: (NSString *) state toState: (NSString *)   statename time: (NSString *) timex container: (NSString *) cont
{
        PajeSetState *set = [[PajeSetState alloc] initWithTime: timex];
        [set setEntityType: [provider aliasToName: statename]];
        [set setValue: [provider aliasToName: state]];
        [set setContainer: cont];
        [set autorelease];
        return set;
}

- (id) cleanBuffer
{
	NSMutableArray *ret;
	ret = [[NSMutableArray alloc] init];
	unsigned int i;

	for (i = 0; i < [buffer count]; i++){
		GEvent *g = [buffer objectAtIndex: i];
		[ret addObjectsFromArray: [self convertEvent: g]];
/*
		GFields *f = [g fields];
		NSString *t = [[f fieldWithSimpleStringKey:@"thread"] description];
		NSString *typeOfThread = [names objectForKey: t];
		if (typeOfThread != nil){
			NSLog (@"typeOfThread defined %@", typeOfThread);
			[ret addObjectsFromArray: [self convertEvent: g]];
			[buffer removeObjectAtIndex: i];
			i = 0;
		}
*/
	}
	[buffer removeAllObjects];
	[ret autorelease];
	return ret;
}

/*
 *
 */
- (id) convertEvent: (GEvent *) event
{
	NSMutableArray *ret = [[NSMutableArray alloc] init];

//	NSLog (@"(%s) event = %@", __FUNCTION__, event);
	
	GFields *f = [event fields];

	gid = [[f fieldWithSimpleStringKey:@"gid"] description];
	cid = [[f fieldWithSimpleStringKey:@"cid"] description];
	time = [[event timestamp] description];
	levelid = [[f fieldWithSimpleStringKey:@"level"] description];
	eventid = [[f fieldWithSimpleStringKey:@"event"] description];
	hostname = [[f fieldWithSimpleStringKey:@"hostname"] description];
	[mappingGidHostname setObject: hostname forKey: gid];
	[mappingGidHostname setObject: gid forKey: hostname];
	
	if (hostname == nil){
		NSString *str;
		str = [NSString stringWithFormat: @"KAAPIConverter (%@): "
			"hostname is not defined. It expect a hostname in "
			"the trace", self];
		[[NSException exceptionWithName: @"DIMVisual-KAAPIConverter" 
			reason: str userInfo: nil] raise];
	}

	NSString *a = [NSString stringWithFormat: @"%@_at_%@", gid, hostname];
	gid = a;

#ifdef SEARCH_THREAD_NAME
	NSString *typeOfThread;
	if ([self isEventUtilThreadName]){
		[self convertEventUtilThreadName: event];
//		NSLog (@"defining name %@ for thread %@", [names objectForKey: cid], cid);
		[ret addObjectsFromArray: [self cleanBuffer]];
		[ret autorelease];
		return ret;
	}

	typeOfThread = [names objectForKey: cid];;
	if (typeOfThread == nil){ 
//		NSLog (@"add type of thread = %@ is null", cid);
		[buffer addObject: event];
		[ret autorelease];
		return ret;
	}
	NSString *threadname = [NSString stringWithFormat: @"%@-%@", cid,
typeOfThread];
	cid = threadname;
#endif

	if (conversionType == Process){
		if ([self isEventUtilThreadName]){
			[self convertEventUtilThreadName: event];
		}

	//      if (![[names objectForKey: cid] isEqual: @"Kthread"]){
	//              [ret autorelease];
	//              return ret;
	//      }
		NSArray *creation = [provider createContainerForEntity:
			[NSArray arrayWithObjects: @"gid", nil]
			ids:
			[NSArray arrayWithObjects: gid, nil]
			time: time];
        	container = [provider identifierForEntity: [NSArray arrayWithObjects: @"gid", nil] ids: [NSArray arrayWithObjects: gid, nil]];
		if ([creation count] != 0){
			[ret addObjectsFromArray: creation];
			[ret addObject: [self addPajeSetState: @"RUNNING"
                   	   toState: @"State" time: time container: container]];
		}
	}else{
		[ret addObjectsFromArray: [provider createContainerForEntity:
			[NSArray arrayWithObjects: @"gid", @"cid", nil]
			ids:
			[NSArray arrayWithObjects: gid, cid, nil]
			time: time]];
        	container = [provider identifierForEntity: [NSArray arrayWithObjects: @"gid", @"cid", nil] ids: [NSArray arrayWithObjects: gid, cid, nil]];
	}

	[ret addObjectsFromArray: [self cleanWorkStealingBuffer]];


	switch (atoi ([levelid cString])){
		case Event::TR_TRACE_LEVEL: 
//			[ret addObjectsFromArray: 
//				[self convertEventTrace: event]];
			break;
		case Event::TR_UTIL_LEVEL: 
//			[ret addObjectsFromArray: 
//				[self convertEventUtil: event]];
			break;
		case Event::TR_KERNEL_LEVEL:
			[ret addObjectsFromArray: 
				[self convertEventKernel: event]];
			break;
		case Event::TR_RFO_LEVEL:
//			[ret addObjectsFromArray: 
//				[self convertEventRFO: event]];
			break;
		case Event::TR_DFG_LEVEL:
//			[ret addObjectsFromArray: 
//				[self convertEventDFG: event]];
			break;
		case Event::TR_WS_LEVEL:
//			[ret addObjectsFromArray: 
//				[self convertEventWS: event]];
			break;
		case Event::TR_NETWORK_LEVEL:
//			[ret addObjectsFromArray: 
//				[self convertEventNetwork: event]];
			break;
		case Event::TR_ST_LEVEL:
//			[ret addObjectsFromArray: 
//				[self convertEventST: event]];
			break;
		case Event::TR_FT_LEVEL:
//			[ret addObjectsFromArray: 
//				[self convertEventFT: event]];
			break;
		default: 
			NSLog (@"Event %d,%d ignored", levelid, eventid);
			break;
	}

	[ret autorelease];
	return ret;
}

- (void) setConversionType: (KAAPIConversionType) convType
{
	conversionType = convType;
}
@end
